﻿/**
 *	Copyright (c) 2009, SpLib.net
 * 	All rights reserved.
  	
 * 	Author:6spring
 * 	About:网络对象管理
*/

package SpLib.ObjSys
{
	import org.dm.general.ClassGather;
	import SpLib.Com.Com;
	import SpLib.Com.SingletonFactory;
	import SpLib.Net.GLID;
	import SpLib.Net.GNID;
	import SpLib.Net.NetMsg;
	import SpLib.Tools.Tr;
	import SpLib.std.iterator;
	import SpLib.std.list;
	import SpLib.std.map;
	import SpLib.std.queue;
		
	public class NetObjMgr
	{
		private static var s_Instance:NetObjMgr = null;
		private static var s_ObjSeed:int = 0;
		private static var s_WndID:int;
		
		private var m_szNetObj:SpLib.std.map;
		private var m_szRegObj:SpLib.std.map;
		private var m_szJoinObj:SpLib.std.list = new SpLib.std.list;
		private var m_szRecvPak:SpLib.std.queue = new SpLib.std.queue();
		private var m_nMaxProcMsgNum:int = 4096;
		
		public function NetObjMgr()
		{
			if(SpLib.ObjSys.NetObjMgr.s_Instance!=null)
			{
				throw new Error("NetObjMgr is Singleton");
			}
			
			s_WndID = Math.random();
			m_szNetObj = new SpLib.std.map(GNID.compare);
			m_szRegObj = new SpLib.std.map(GOID.compare);
			
			SpLib.Com.Com.AddUpdateFunc(OnProcTime);
		}
		
		public static function GetInstance():NetObjMgr
		{
			var name:String = "SpLib.ObjSys.NetObjMgr";
			if(s_Instance==null)
			{
				s_Instance = SingletonFactory.Get(name) as SpLib.ObjSys.NetObjMgr;
				if(s_Instance==null)
				{			
					s_Instance = new SpLib.ObjSys.NetObjMgr();
					SingletonFactory.Reg(name,s_Instance);
				}
			}
			
			return s_Instance;
		}
		
		public function SetMaxProcMsgNum(num:int):void
		{
			m_nMaxProcMsgNum = num;
		}
		
		public function AddJoin(gnid:GNID,thisobj:NetObjC):Boolean
		{
			var iter:SpLib.std.iterator = m_szJoinObj.begin();
			while(iter!=null)
			{
				var obj:NetObjC = iter.m_Data as NetObjC;
				if(obj.m_bDeled)
				{
					iter = m_szJoinObj.erase(iter);
				}
				else
				{
					if(obj.m_GNID.equal(gnid))
					{
						return false;
					}
					
					iter = iter.next;
				}
			}
			
			m_szJoinObj.push_back(thisobj);
			return true;
		}
		
		public function PopJoin(gnid:GNID):NetObjC
		{
			var iter:SpLib.std.iterator = m_szJoinObj.begin();
			while(iter!=null)
			{
				var obj:NetObjC = iter.m_Data as NetObjC;
				if(obj.m_bDeled)
				{
					iter = m_szJoinObj.erase(iter);
				}
				else
				{
					if(obj.m_GNID.equal(gnid))
					{
						m_szJoinObj.erase(iter);
						return obj;
					}
					
					iter = iter.next;
				}
			}
			
			return null;
		}
		
		public static function SendTo(glid:GLID,goid:GOID,evename:String,agv:Array):void
		{
			var msg:SpLib.Net.NetMsg = new SpLib.Net.NetMsg();
			msg.m_nMsgtype = SpLib.Net.NetMsg.TYPE_P2PDATA;
			
			msg.m_Address.m_nServiceID = glid.m_nIP;
			msg.m_Address.m_nGroupID = glid.m_nTypePort;
			msg.m_Address.m_nObjIDH = glid.m_nObjIDH;
			msg.m_Address.m_nObjIDL = glid.m_nObjIDL;
		
			msg.m_Value = new Array;
			msg.m_Value.push(goid.GetAsArray());
			msg.m_Value.push(agv);
			
			SpLib.Net.NetMsgMgr.SendMsg(msg);
		}
		
		public static function RegP2PObj(obj:SpLib.ObjSys.BaseObj):SpLib.ObjSys.GOID
		{
			var goid:SpLib.ObjSys.GOID = new SpLib.ObjSys.GOID();
			goid.m_nWndIDL = s_WndID;
			goid.m_nObjIDL = ++s_ObjSeed;
			GetInstance().m_szRegObj.insert(goid,obj);
			return goid;
		}
		
		public static function UnRegP2PObj(goid:SpLib.ObjSys.GOID):void
		{
			GetInstance().m_szRegObj.remove(goid);
		}
		
		public static function FindP2PObj(goid:GOID):BaseObj
		{
			var iter:SpLib.std.iterator = GetInstance().m_szRegObj.find(goid);
			if(iter==null) return null;
			
			var obj:BaseObj = iter.m_Data as BaseObj;
			if(obj.m_bDeled)
			{
				GetInstance().m_szRegObj.erase(iter);
				return null;
			}
			return obj;
		}
		
		public static function Add(gnid:GNID,obj:NetObjC):Boolean
		{
			return GetInstance().m_szNetObj.insert(gnid,obj);
		}
		
		public static function Find(gnid:GNID):NetObjC
		{
			var iter:SpLib.std.iterator = GetInstance().m_szNetObj.find(gnid);
			if(iter==null) return null;
			
			var obj:NetObjC = iter.m_Data as NetObjC;
			if(obj.m_bDeled)
			{
				GetInstance().m_szNetObj.erase(iter);
				return null;
			}
			
			return obj;
		}
		
		public static function Del(gnid:GNID):void
		{
			GetInstance().m_szNetObj.remove(gnid);
		}
		
		public static function DelService(sid:int):void
		{
			var iter:SpLib.std.iterator = GetInstance().m_szNetObj.begin();
			while(iter!=null)
			{
				var obj:NetObjC = iter.m_Data as NetObjC;
				if(obj.m_bDeled)
				{
					iter = GetInstance().m_szNetObj.erase(iter);
				}
				else
				{
					if(obj.m_GNID.m_nServiceID==sid)
					{
						obj.ServiceBreak(sid);
						obj.DelObj();
						iter = GetInstance().m_szNetObj.erase(iter);
					}
					else
					{
						iter = iter.next;
					}
				}
			}
		}
		
		public function _DelGroup(sid:int,gid:int):void
		{
			var iter:SpLib.std.iterator = m_szNetObj.begin();
			while(iter!=null)
			{
				var obj:NetObjC = iter.m_Data as NetObjC;
				if(obj.m_bDeled)
				{
					iter = m_szNetObj.erase(iter);
				}
				else
				{
					if(obj.m_GNID.m_nServiceID==sid && obj.m_GNID.m_nGroupID==gid)
					{
						obj.DelObj();
						iter = m_szNetObj.erase(iter);
					}
					else
					{
						iter = iter.next;
					}
				}
			}
		}
		
		public static function DelGroup(sid:int,gid:int):void
		{
			GetInstance()._DelGroup(sid,gid);
		}
		
		public static function Msg(msg:NetMsg):void
		{
			GetInstance().m_szRecvPak.push(msg);
			GetInstance().OnProcTime();
		}
		
		private function OnProcTime():void
		{
			var i:int;
			for(i=0;i<m_nMaxProcMsgNum;i++)
			{
				var msg:NetMsg = m_szRecvPak.pop() as NetMsg;
				if(msg==null)
					break;
				else
					ProcMsg(msg);
			}
		}
		
		private function ProcMsg(msg:NetMsg):void
		{
			trace(msg.m_nMsgtype+"-----"+msg.m_Value);
			
			var netobj:NetObjC;
			var gnid:SpLib.Net.GNID;
			
			switch(msg.m_nMsgtype)
			{
			case NetMsg.TYPE_SESSION_SENDC:
			{
				netobj = Find(msg.m_Address);
				if(netobj!=null)
				{
					netobj.EventAsID(msg.m_nEveID,msg.m_Value);
				}
			}
			break;
			case NetMsg.TYPE_SESSION_JOIN_RESP:
			{
				if(msg.m_nEveID==1)
				{
					gnid = new SpLib.Net.GNID(msg.m_Value);
					
					netobj = GetInstance().PopJoin(msg.m_Address);
					if(netobj!=null)
					{
						Add(gnid,netobj);
						netobj.JoinGruopOk(msg.m_GLID,gnid);
					}
				}
				else
				{
					netobj = GetInstance().PopJoin(msg.m_Address);
					if(netobj!=null)
					{
						netobj.JoinGroupErr( msg.m_Value[0] as int, msg.m_Value[1] as String);
					}
				}
			}
			break;	
			case NetMsg.TYPE_MIRROR_CREATE:
			{
				var mainobj:NetObjC = Find(msg.m_Address);
				if(mainobj!=null)
				{
					var classname:String = msg.m_Value[0] as String;
					switch (classname) 
					{
						case "CGameDesk":
							classname = "net.minDesk";
							break;
						case "CRoomUser":
							classname = "net.userData";
							break;
					}
					gnid = new SpLib.Net.GNID(msg.m_Value[1] as Array);
					
					netobj = ClassGather.getInstance(classname);
					if(netobj!=null)
					{
						netobj.RemouteCreate(msg.m_GLID,gnid,msg.m_Value[2] as Array);
						Add(gnid,netobj);
					}
					else
					{
						SpLib.Tools.Tr.Error("创建对象" + classname + "成功");
					}
				}
			}
			break;
			case NetMsg.TYPE_MIRROR_DESTROY:
			{
				netobj = Find(msg.m_Address);
				if(netobj!=null)
				{
					netobj.DelObj();
					Del(msg.m_Address);
				}
			}
			break;
			case NetMsg.TYPE_KICK:
			{
				netobj = Find(msg.m_Address);
				if(netobj!=null)
				{
					if(netobj.m_bIsMainPlayer)
					{
						netobj.BreakPlayer(msg.m_Value[0] as int,msg.m_Value[1] as String);
						netobj.DelObj();
						DelGroup(msg.m_Address.m_nServiceID,msg.m_Address.m_nGroupID);
					}
				}
			}
			break;
			case NetMsg.TYPE_SERVICEBREAK:
			{
				DelService(msg.m_Address.m_nServiceID);
			}
			break;
			case NetMsg.TYPE_P2PDATA:
			{
				var goid:GOID = new GOID(msg.m_Value[0] as Array);
				var p2pobj:BaseObj = FindP2PObj(goid);
				if(p2pobj!=null && p2pobj.m_bDeled)
				{
					p2pobj.EventAsID(msg.m_nEveID,msg.m_Value[1] as Array);
				}
			}
			break;
			}
		}
	}
}